package com.sailing.xjpb.dict.translate.handler;

import com.google.common.collect.Maps;
import com.sailing.xjpb.common.SailingReflectionUtils;
import com.sailing.xjpb.common.web.translate.TranslateHandler;
import com.sailing.xjpb.dict.translate.annotation.EnumField;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 枚举翻译处理器：处理VO标注有@EnumField注解的字段翻译
 *
 * @author YaoWei
 */
@Slf4j
public class EnumTranslateHandler implements TranslateHandler {

    @Override
    public void doTranslate(Class<?> itemClass, List<Field> translateFields, Collection<?> datas) {
        try {
            // 获取需要翻译的枚举信息
            Map<String, Map<String, String>> translateDicts = getTranslateDicts(translateFields);
            for (Field field : translateFields) {
                for (Object data : datas) {
                    EnumField dictField = field.getAnnotation(EnumField.class);
                    String sourceFieldName = dictField.sourceField();
                    String targetFieldName = field.getName();
                    String splitter = dictField.splitter();
                    String dictCode = this.getValue(itemClass, data, sourceFieldName);
                    Map<String, String> kvMap = translateDicts.get(field.getName());
                    if (kvMap == null || StringUtils.isBlank(dictCode)) {
                        continue;
                    }
                    String translatedValue = this.doTranslate(dictCode, splitter, kvMap);
                    SailingReflectionUtils.setField(field, data, translatedValue);
                    if (log.isDebugEnabled()) {
                        log.debug("字典翻译：class={}==>sourceField={}->targetFieldName={}->value={}", itemClass,
                                sourceFieldName,
                                targetFieldName, translatedValue);
                    }
                }
            }
        } catch (Exception e) {
            log.error("字典翻译出错：{}", e.getMessage());
        }
    }

    @Override
    public SailingReflectionUtils.FieldFilter getTranslateFieldFilter() {
        return field -> field.getAnnotation(EnumField.class) != null;
    }

    @Override
    public int getOrder() {
        return 2;
    }

    /**
     * 获取DictField配置的dictType属性对应的枚举信息
     *
     * @param fields 标注有DictField的枚举信息
     * @author YaoWei
     * createDate 2020年11月13日 下午3:41:59
     * editDate 2020年11月13日 下午3:41:59
     */
    private Map<String, Map<String, String>> getTranslateDicts(List<Field> fields) {
        Map<String, Map<String, String>> dictInfo = Maps.newHashMap();
        try {
            for (Field field : fields) {
                EnumField enumField = field.getAnnotation(EnumField.class);
                String[] enumKv = enumField.enumKv();
                Map<String, String> kvMap = new HashMap<>(2);
                for (String kv : enumKv) {
                    String[] kvArray = kv.split("_");
                    kvMap.put(kvArray[0], kvArray[1]);
                }
                dictInfo.put(field.getName(), kvMap);
            }
        } catch (Exception e) {
            log.warn("枚举字典信息解析出错！", e);
        }
        return dictInfo;
    }

    /**
     * 获取翻译后的枚举值，如果没有翻译成功，返回code
     *
     * @param originDictCode 枚举codes
     * @param kvMap          所有枚举值
     * @author YaoWei
     * createDate 2020年11月13日 下午3:42:50
     * editDate 2020年11月13日 下午3:42:50
     */
    private String doTranslate(String originDictCode, String splitter, Map<String, String> kvMap) {
        String[] dictCodes = originDictCode.split(splitter);
        List<String> dictValues = new ArrayList<>(dictCodes.length);
        Arrays.stream(dictCodes).filter(kvMap::containsKey).forEach(v -> dictValues.add(kvMap.get(v)));
        return dictValues.isEmpty() ? originDictCode : StringUtils.join(dictValues, splitter);
    }

    private String getValue(Class<?> itemClass, Object data, String sourceFieldName) {
        Field sourceField = SailingReflectionUtils.findAndMakeAccessible(itemClass, sourceFieldName);
        Object sourceFieldValue = SailingReflectionUtils.getField(sourceField, data);
        return Objects.toString(sourceFieldValue, null);
    }
}
